﻿namespace Microsoft.VisualStudio.IDE.ToolboxControlsInstaller
{
    using Microsoft.Win32;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.Versioning;
    using System.Security;
    using System.Security.Cryptography;
    using System.Text;

    internal class NonCachedAssemblyFolder : AssemblyFolder
    {
        private List<RegisteredAssembly> _assemblies;
        private readonly string _defaultCategory;
        private readonly string _folderPath;
        private readonly Action<string> _log;
        private readonly string _tfm;
        private static SHA512 hashAlgorithm = SHA512.Create();

        public NonCachedAssemblyFolder(string tfm, string folderPath, string defaultCategory, Action<string> log)
        {
            this._tfm = tfm;
            this._folderPath = folderPath ?? "";
            this._defaultCategory = defaultCategory ?? "";
            this._log = log;
        }

        public void Cache(RegistryKey userSettings, string key, byte[] regHash)
        {
            string subkey = @"ToolboxControlsInstaller_AssemblyFoldersExCache\" + key.Replace('\\', '_');
            try
            {
                userSettings.DeleteSubKeyTree(subkey);
            }
            catch (ArgumentException)
            {
            }
            using (RegistryKey key2 = userSettings.CreateSubKey(subkey))
            {
                key2.SetValue("RegistryHash", regHash);
                key2.SetValue("TargetFramework", this._tfm);
                foreach (RegisteredAssembly assembly in this.GetAssemblies())
                {
                    using (RegistryKey key3 = key2.CreateSubKey(assembly.AssemblyName.FullName))
                    {
                        key3.SetValue("AssemblyType", assembly.Identifier);
                        key3.SetValue("DefaultCategory", assembly.DefaultCategory);
                        key3.SetValue("AssemblyHash", assembly.RegistryHash);
                        key3.SetValue("Codebase", assembly.AssemblyName.CodeBase);
                        continue;
                    }
                }
            }
        }

        public override IEnumerable<RegisteredAssembly> GetAssemblies()
        {
            if (this._assemblies == null)
            {
                this._assemblies = new List<RegisteredAssembly>();
                try
                {
                    foreach (string str in Directory.GetFiles(this._folderPath, "*.dll"))
                    {
                        try
                        {
                            RegisteredAssembly assembly2;
                            Assembly assembly = Assembly.ReflectionOnlyLoadFrom(str);
                            if (this.IsSilverlightTfm(this._tfm))
                            {
                                assembly2 = new SilverlightAssembly(assembly.GetName());
                            }
                            else if (this.ReferencesPresentationFramework(assembly))
                            {
                                assembly2 = new WPFAssembly(assembly.GetName());
                            }
                            else
                            {
                                assembly2 = new DotNetAssembly(assembly.GetName());
                            }
                            assembly2.DefaultCategory = this._defaultCategory;
                            assembly2.TargetFramework = this._tfm;
                            assembly2.RegistryHash = hashAlgorithm.ComputeHash(File.ReadAllBytes(str).Concat<byte>(Encoding.UTF8.GetBytes(this._defaultCategory + assembly.GetName().CodeBase)).ToArray<byte>());
                            this._assemblies.Add(assembly2);
                        }
                        catch (BadImageFormatException)
                        {
                            this._log(str + " was not a valid assembly (Assembly.ReflectionOnlyLoadFrom threw BadImageFormatException).");
                        }
                        catch (FileNotFoundException)
                        {
                            this._log(str + " was returned from Directory.GetFiles but was not found on disk (Assembly.ReflectionOnlyLoadFrom threw FileNotFoundException).");
                        }
                        catch (FileLoadException)
                        {
                            this._log(str + " could not be loaded (Assembly.ReflectionOnlyLoadFrom threw FileLoadException).");
                        }
                        catch (SecurityException)
                        {
                            this._log(str + " could not be loaded due to a security violation (Assembly.ReflectionOnlyLoadFrom threw SecurityException).");
                        }
                    }
                }
                catch (UnauthorizedAccessException)
                {
                    this._log("You do not have permission to access " + this._folderPath + " (Directory.GetFiles threw UnauthorizedAccessException).");
                }
                catch (PathTooLongException)
                {
                    this._log(this._folderPath + " exceeds the maximum allowed path length (Directory.GetFiles threw PathTooLongException).");
                }
                catch (DirectoryNotFoundException)
                {
                    this._log(this._folderPath + " was not found (Directory.GetFiles threw DirectoryNotFoundException).");
                }
                catch (ArgumentException)
                {
                    this._log("'" + this._folderPath + "' is not a valid path (Directory.GetFiles threw ArgumentException).");
                }
            }
            return this._assemblies;
        }

        private bool IsSilverlightTfm(string tfm)
        {
            FrameworkName name = new FrameworkName(tfm);
            return (string.Compare(name.Identifier, "Silverlight", StringComparison.OrdinalIgnoreCase) == 0);
        }

        private bool ReferencesPresentationFramework(Assembly assembly)
        {
            return assembly.GetReferencedAssemblies().Any<AssemblyName>(n => (string.Compare(n.Name, "PresentationFramework", StringComparison.OrdinalIgnoreCase) == 0));
        }
    }
}

